package com.twang.stock.utils.http;

import org.apache.http.Header;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.StringUtils;

import javax.net.ssl.*;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLEncoder;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.Set;

public class HttpStockUtils {
	private final String CTYPE_FORM = "application/x-www-form-urlencoded;charset=utf-8";
	private final String CTYPE_JSON = "application/json; charset=utf-8";
	private final String charset = "utf-8";


	public static final String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36";
	public static String COOKIE = "v=A3mH6ooqPRK0e-GGeAjFux6xiO5Qhm04V3qRzJuu9aAfIpcY49Z9COfKoZ0o";

	public static String URL = "http://q.10jqka.com.cn/api.php?t=indexflash&";

	private static HttpStockUtils instance = null;

	public static HttpStockUtils getInstance() {
		if (instance == null) {
			return new HttpStockUtils();
		}
		return instance;
	}

	private class DefaultTrustManager implements X509TrustManager {
		public X509Certificate[] getAcceptedIssuers() {
			return null;
		}

		@Override
		public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
		}

		@Override
		public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
		}
	}

	/**
	 * 以application/json; charset=utf-8方式传输
	 *
	 * @param url
	 * @return
	 * @throws SocketTimeoutException
	 * @throws IOException
	 */
	public String postJson(String url, String jsonContent) throws SocketTimeoutException, IOException {
		return doRequest("POST", url, jsonContent, 15000, 15000, CTYPE_JSON, null);
	}

	/**
	 * POST 以application/x-www-form-urlencoded;charset=utf-8方式传输
	 *
	 * @param url
	 * @return
	 * @throws SocketTimeoutException
	 * @throws IOException
	 */
	public String postForm(String url) throws SocketTimeoutException, IOException {
		return doRequest("POST", url, "", 15000, 15000, CTYPE_FORM, null);
	}

	/**
	 * POST 以application/x-www-form-urlencoded;charset=utf-8方式传输
	 *
	 * @param url
	 * @return
	 * @throws SocketTimeoutException
	 * @throws IOException
	 */
	public String postForm(String url, Map<String, String> params) throws SocketTimeoutException, IOException {
		return doRequest("POST", url, buildQuery(params), 15000, 15000, CTYPE_FORM, null);
	}

	/**
	 * POST 以application/x-www-form-urlencoded;charset=utf-8方式传输
	 *
	 *
	 * @param url
	 * @return
	 * @throws SocketTimeoutException
	 * @throws IOException
	 */
	public String getForm(String url) throws SocketTimeoutException, IOException {
		return doRequest("GET", url, "", 15000, 15000, CTYPE_FORM, null);
	}

	/**
	 * POST 以application/x-www-form-urlencoded;charset=utf-8方式传输
	 *
	 * @param url
	 * @return
	 * @throws SocketTimeoutException
	 * @throws IOException
	 */
	public String getForm(String url, Map<String, String> params) throws SocketTimeoutException, IOException {
		return doRequest("GET", url, buildQuery(params), 15000, 15000, CTYPE_FORM, null);
	}

	private  String doRequest(String method, String url, String requestContent, int connectTimeout, int readTimeout, String ctype, Map<String, String> headerMap)
			throws SocketTimeoutException, IOException {
		HttpURLConnection conn = null;
		OutputStream out = null;
		String rsp = null;
		try {
			conn = getConnection(new URL(url), method, ctype, headerMap);
			conn.setConnectTimeout(connectTimeout);
			conn.setReadTimeout(readTimeout);

			if (!StringUtils.isEmpty(requestContent)) {
				out = conn.getOutputStream();
				out.write(requestContent.getBytes(charset));
			}

			rsp = getResponseAsString(conn);
		} finally {
			if (out != null) {
				out.close();
			}
			if (conn != null) {
				conn.disconnect();
			}
			conn = null;
		}
		return rsp;
	}

	private  HttpURLConnection getConnection(URL url, String method, String ctype, Map<String, String> headerMap) throws IOException {
		HttpURLConnection conn;
		if ("https".equals(url.getProtocol())) {
			SSLContext ctx;
			try {
				ctx = SSLContext.getInstance("TLS");
				ctx.init(new KeyManager[0], new TrustManager[] { new DefaultTrustManager() }, new SecureRandom());
			} catch (Exception e) {
				throw new IOException(e);
			}
			HttpsURLConnection connHttps = (HttpsURLConnection) url.openConnection();
			connHttps.setSSLSocketFactory(ctx.getSocketFactory());
			connHttps.setHostnameVerifier(new HostnameVerifier() {
				public boolean verify(String hostname, SSLSession session) {
					return true;
				}
			});
			conn = connHttps;
		} else {
			conn = (HttpURLConnection) url.openConnection();
		}
		conn.setRequestMethod(method);
		conn.setDoInput(true);
		conn.setDoOutput(true);
		conn.setRequestProperty("Accept", "text/xml,text/javascript,text/html,application/json");
		conn.setRequestProperty("Content-Type", ctype);
		if (headerMap != null) {
			for (Map.Entry<String, String> entry : headerMap.entrySet()) {
				conn.setRequestProperty(entry.getKey(), entry.getValue());
			}
		}
		return conn;
	}

	private  String getResponseAsString(HttpURLConnection conn) throws IOException {
		InputStream es = conn.getErrorStream();
		if (es == null) {
			return getStreamAsString(conn.getInputStream(), charset, conn);
		} else {
			String msg = getStreamAsString(es, charset, conn);
			if (StringUtils.isEmpty(msg)) {
				throw new IOException(conn.getResponseCode() + ":" + conn.getResponseMessage());
			} else {
				return msg;
			}
		}
	}

	private  String getStreamAsString(InputStream stream, String charset, HttpURLConnection conn) throws IOException {
		try {
			Reader reader = new InputStreamReader(stream, charset);

			StringBuilder response = new StringBuilder();
			final char[] buff = new char[1024];
			int read = 0;
			while ((read = reader.read(buff)) > 0) {
				response.append(buff, 0, read);
			}

			return response.toString();
		} finally {
			if (stream != null) {
				stream.close();
			}
		}
	}

	private String buildQuery(Map<String, String> params) throws IOException {
		if (params == null || params.isEmpty()) {
			return "";
		}

		StringBuilder query = new StringBuilder();
		Set<Map.Entry<String, String>> entries = params.entrySet();
		boolean hasParam = false;

		for (Map.Entry<String, String> entry : entries) {
			String name = entry.getKey();
			String value = entry.getValue();
			if (hasParam) {
				query.append("&");
			} else {
				hasParam = true;
			}
			query.append(name).append("=").append(URLEncoder.encode(value, charset));
		}
		return query.toString();
	}

	/**
	 * 获取GET请求
	 * @param url
	 * @return
	 * @throws Exception
	 */
	public static String getHtmlStrByUrl(String url) throws Exception {
		// HttpClient 超时配置
		RequestConfig globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD)
				.setConnectionRequestTimeout(6000).setConnectTimeout(6000).build();
		CloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(globalConfig).build();

		HttpGet httpGetForFName = new HttpGet(url);
		httpGetForFName.addHeader("User-Agent", USER_AGENT);
		httpGetForFName.addHeader("Cookie", getCOOKIE());
		httpGetForFName.addHeader("Content-Type", "text/html; charset=gbk");
		httpGetForFName.addHeader("Accept-Encoding", "gzip, deflate");
		httpGetForFName.addHeader("Connection", "keep-alive");
		// 发送请求，并执行
		CloseableHttpResponse response;
		String html = "";
		try {
			response = httpClient.execute(httpGetForFName);
			// response植入cookie
			Header[] ssoResponseHeader = response.getHeaders("Set-Cookie");
			InputStream in = response.getEntity().getContent();
			html = convertStreamToString(in,"gbk");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return html;
	}


	public static String getHtmlStrByUrlPOST(String url,String key) throws Exception {
		// HttpClient 超时配置
		RequestConfig globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD)
				.setConnectionRequestTimeout(6000).setConnectTimeout(6000).build();
		CloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(globalConfig).build();

		HttpPost httppotForFName = new HttpPost(url);
		httppotForFName.setHeader("User-Agent", "PostmanRuntime/7.26.8");
		httppotForFName.setHeader("Cookie",getCOOKIE() );
		httppotForFName.setHeader("Content-Type", "application/json");
		httppotForFName.setHeader("Accept-Encoding", "gzip, deflate, br");
		httppotForFName.setHeader("Connection", "keep-alive");
		httppotForFName.setHeader("Accept", "*/*");

		// 发送请求，并执行
		CloseableHttpResponse response;
		String html = "";
		try {

			// 设置请求参数
			//{"source":"Ths_iwencai_Xuangu","version":"2.0","query_area":"","block_list":"","add_info":"{\"urp\":{\"scene\":1,\"company\":1,\"business\":1},\"contentType\":\"json\",\"searchInfo\":true}","question":"今年涨幅前30个股","perpage":50,"page":1,"secondary_intent":"stock","log_info":"{\"input_type\":\"typewrite\"}","rsh":"Ths_iwencai_Xuangu_d09h1x2uoqfoch2di7ndckx2aa5ividi"}
			// String jsonBody="{\"source\":\"Ths_iwencai_Xuangu\",\"version\":\"2.0\",\"question\":\""+key+"\"}";
			String jsonBody="{\"source\":\"Ths_iwencai_Xuangu\",\"version\":\"2.0\",\"query_area\":\"\",\"block_list\":\"\",\"add_info\":\"{\\\"urp\\\":{\\\"scene\\\":1,\\\"company\\\":1,\\\"business\\\":1},\\\"contentType\\\":\\\"json\\\",\\\"searchInfo\\\":true}\",\"question\":\"今年涨幅前30个股\",\"perpage\":50,\"page\":1,\"secondary_intent\":\"stock\",\"log_info\":\"{\\\"input_type\\\":\\\"typewrite\\\"}\",\"rsh\":\"Ths_iwencai_Xuangu_d09h1x2uoqfoch2di7ndckx2aa5ividi\"}";
			// 将参数编码为表单数据
			StringEntity entity = new StringEntity(jsonBody,"UTF-8");
			// 设置请求体
			httppotForFName.setEntity(entity);
			response = httpClient.execute(httppotForFName);
			InputStream in = response.getEntity().getContent();
			html = convertStreamToString(in,"utf-8");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return html;
	}
	public static String convertStreamToString(InputStream in,String type) {
		StringBuilder sb = new StringBuilder();
		try {

			InputStreamReader isr = new InputStreamReader(in, type);
			BufferedReader reader = new BufferedReader(isr);
			String line = null;
			while ((line = reader.readLine()) != null) {
				sb.append(line + "/n");
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				in.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return sb.toString();

	}

	/**
	 * 获取GET请求
	 * @param url
	 * @return
	 * @throws Exception
	 */
	public static String getHtmlStrByUrlUtf8(String url) throws Exception {
		// HttpClient 超时配置
		RequestConfig globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD)
				.setConnectionRequestTimeout(6000).setConnectTimeout(6000).build();
		CloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(globalConfig).build();

		HttpGet httpGetForFName = new HttpGet(url);
		httpGetForFName.addHeader("User-Agent", USER_AGENT);
		httpGetForFName.addHeader("Cookie", getCOOKIE());
		httpGetForFName.addHeader("Content-Type", "text/html; charset=utf-8");
		httpGetForFName.addHeader("Accept-Encoding", "gzip, deflate");
		httpGetForFName.addHeader("Connection", "keep-alive");
		// 发送请求，并执行
		CloseableHttpResponse response;
		String html = "";
		try {
			response = httpClient.execute(httpGetForFName);
			// response植入cookie
			Header[] ssoResponseHeader = response.getHeaders("Set-Cookie");
			InputStream in = response.getEntity().getContent();
			html = convertStreamToStringUtf8(in);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return html;
	}
	public static String convertStreamToStringUtf8(InputStream in) {
		StringBuilder sb = new StringBuilder();
		try {

			InputStreamReader isr = new InputStreamReader(in, "utf-8");
			BufferedReader reader = new BufferedReader(isr);
			String line = null;
			while ((line = reader.readLine()) != null) {
				sb.append(line + "/n");
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				in.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return sb.toString();

	}

	public static String getCOOKIE() throws Exception {
		ScriptEngineManager manager = new ScriptEngineManager();
		ScriptEngine engine = manager.getEngineByName("javascript");
		// String jsFileName = GaiNianZiJingPaiHangTask.class.getClassLoader().getResource("static/js/aes.min.js").getFile(); // 读取js文件
		// FileReader reader = new FileReader(); // 执行指定脚本
		//spring boot 不能直接这样读取路径，jar包中会报错
		ClassPathResource classPathResource = new ClassPathResource("static/js/aes.min.js");
		InputStreamReader reader = new InputStreamReader(classPathResource.getInputStream());
		engine.eval(reader);
		if (engine instanceof Invocable) {
			Invocable invoke = (Invocable) engine; // 调用merge方法，并传入两个参数
			// c = merge(2, 3);
			String c = (String) invoke.invokeFunction("v");
			COOKIE = "v=" + c;
		}
		reader.close();
		return COOKIE;
	}
}
